﻿using System;
using StockholmsStad.Windows.UI.Infrastructure.Properties;

namespace StockholmsStad.Windows.UI.Infrastructure.ValidationRules
{
    public class PersonalNumberValidationRule
    {
        public static bool IsValidBirthdayNumber(string birthdayNumber, bool swedishNationality, out string errorMessage)
        {
            errorMessage = string.Empty;

            if (string.IsNullOrEmpty(birthdayNumber))
            {
                errorMessage = Resources.BirthdayMustBeProvided;
                return false;
            }

            // giltiga p-nr är: YYYYMMDD-XXXX/0000 alt YYYYMMDD för utländska

            // Antal tecken
            if (!(birthdayNumber.Length == 13 || birthdayNumber.Length == 12))
            {
                if (swedishNationality || birthdayNumber.Length != 8)
                {
                    errorMessage = Resources.InvalidBirthdayNumber;
                    return false;
                }
            }

            string inputString = birthdayNumber.Replace("-", "");

            long longValue;
            if (long.TryParse(inputString, out longValue) == false)
            {
                errorMessage = Resources.InvalidBirthdayNumber;
                return false;
            }

            if (!DateTimeFormat.IsValidDate(inputString.Substring(0, 8)))
            {
                errorMessage = Resources.InvalidDate;
                return false;
            }

            //Utlänningar kan ha endast datum
            if(!swedishNationality && birthdayNumber.Length == 8)
                return true;

            int index = inputString.IndexOf("0000");

            if (index > 0)
                return true;

            // validate last 4 numbers 
            if (!IsValidNumber(inputString.Substring(2, inputString.Length - 2)))
            {
                errorMessage = Resources.InvalidCheckNumber;
                return false;
            }

            return true;
        }

        /// <summary>
        /// Kontrollera att kontrollnumret i angivet identifikationsnummer är korrekt.
        /// </summary>
        /// <param name="idNumber">Id-nummer inklusive kontrollsiffra.</param>
        /// <returns>True/False</returns>
        private static bool IsValidNumber(string idNumber)
        {
            var controlNumber = 0;
            return controlNumber == CalculateControlNumber(idNumber);
        }

        /// <summary>
        /// Beräkna kontrollsiffran i ett identifikationsnummer.
        /// </summary>
        /// <param name="idNumber">Id-nummer exklusive kontrollsiffra.</param>
        /// <returns>Kontrollsiffran för id-numret.</returns>
        private static int CalculateControlNumber(string idNumber)
        {
            var controlNumber = 0;

            var idNumberChars = idNumber.ToCharArray();

            var newNumber = 0;

            var include = true;

            for (var charCount = 0; charCount < idNumberChars.Length; charCount++)
            {
                var number = Convert.ToInt32(idNumberChars[charCount].ToString());
                if (include)
                    number *= 2;

                include = !include;

                if (number > 9)
                    number -= 9;

                newNumber += number;
            }

            var newNumberAsString = newNumber.ToString();

            var last = newNumberAsString.Substring(newNumberAsString.Length - 1);
            controlNumber = 10 - Convert.ToInt32(last);

            if (controlNumber == 10)
                controlNumber = 0;

            return controlNumber;
        }
    }

    public class DateTimeFormat
    {
        private const int DATE_LENGTH = 8;

        public static bool IsValidDate(string date)
        {
            DateTime validDate;

            if (DateTime.TryParse(Format(date), out validDate))
                return true;

            return false;
        }

        private static string Format(string arg)
        {
            if (String.IsNullOrEmpty(arg))
                throw new ArgumentNullException("arg");

            if (arg.Length != DATE_LENGTH)
                throw new InvalidOperationException("Invalid input format");

            // Insert - at position 4 and 6
            var newString = arg.Insert(6, "-").Insert(4, "-");

            return newString;
        }
    }
}
